package cn.duhengkui.national.valuelist.core.data.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeanUtils;

import cn.duhengkui.national.valuelist.annotation.Column;
import cn.duhengkui.national.valuelist.annotation.Entity;
import cn.duhengkui.national.valuelist.annotation.EntityType;
import cn.duhengkui.national.valuelist.context.EntityContext;
import cn.duhengkui.national.valuelist.core.data.exception.DAORunTimeException;
import cn.duhengkui.national.valuelist.core.entity.BaseEntity;
import cn.duhengkui.national.valuelist.core.entity.BaseObject;


/**   
 * <table border="1">
 *	<tr><td>包名称：</td><td>cn.duhengkui.national.valuelist.core.data.util</td></tr>
 *	<tr><td>类名称：</td><td>Entitys</td></tr>
 *	<tr><td>类描述：</td><td>实体对象的元数据信息</td></tr>
 *	<tr><td>创建人：</td><td>杜恒奎</td></tr>
 *  <tr><td>创建时间：</td><td>2018年6月7日/下午3:10:48</td></tr> 
 *  <tr><td>版本：</td><td>1.0.0</td></tr>
 * </table>   
 *     
 */
public class Entitys {

	public static final String COLUMN_SPLIT = ",";
	
	private final Map<String, EntityAttribute> pkMap = new HashMap<>(1);
	
	private final Map<Integer, EntityAttribute> sortMap = new LinkedHashMap<>(0);
	
	private String name;
	
	private EntityType type;
	
	private boolean identityPk;
	
	private boolean UUIDPk;
	
	private List<EntityAttribute> list = new ArrayList<>();
	
	private Map<String, Method> columnSetterMap = new HashMap<>();
	
	private boolean hasAnnotation = true;
	
	private Entitys(Class<? extends BaseEntity> clazz) {
		searchEntity(clazz);
	}
	
	/**
	 * 是否当前实体的属性
	 * @param attribute
	 * @return
	 */
	public boolean isCurrentAttribute(final EntityAttribute attribute) {
		boolean flag = false;
		for(EntityAttribute entityAttribute : list) {
			if(entityAttribute.getName().equals(attribute.getName()) || entityAttribute.getAttributeName().equals(attribute.getAttributeName())) {
				BeanUtils.copyProperties(entityAttribute, attribute);
				flag = true;
				break;
			}
		}
		return flag;
	}
	
	/**
	 * 获得一个新的实例
	 * @param clazz 实体对象class
	 * @return Entitys对象
	 */
	public static Entitys newInstance(Class<? extends BaseEntity> clazz) {
		if(EntityContext.exists(clazz)) {
			return EntityContext.getEntity(clazz);
		} else {
			return new Entitys(clazz);
		}
	}
	
	/**
	 * 获得一个新的实例
	 * @param entity 实体对象
	 * @return
	 */
	public static Entitys newInstance(BaseEntity entity) {
		return newInstance(entity.getClass());
	}
	
	
	/**
	 * 根据实体元数据生成查询SQL语句
	 * @return 查询SQL语句
	 */
	public String createSelect() {
		StringBuffer sql = new StringBuffer();
//		String alias = type == EntityType.SCRIPT ? "t." : "t.";
		String alias = "t.";
		String entityName = type == EntityType.SCRIPT ? "(" + name + ") t" : name + " t";
		sql.append("SELECT ");
		for(EntityAttribute entityAttribute : list) {
			sql.append(alias).append(entityAttribute.getName()).append(COLUMN_SPLIT);
		}
		sql.delete(sql.lastIndexOf(COLUMN_SPLIT), sql.lastIndexOf(COLUMN_SPLIT) + 1);
		sql.append(" FROM ");
		sql.append(entityName);
		return sql.toString();
	}
	
	public Map<String, EntityAttribute> getPkMap() {
		return pkMap;
	}

	public Map<Integer, EntityAttribute> getSortMap() {
		return sortMap;
	}

	public String getName() {
		return name;
	}

	public EntityType getType() {
		return type;
	}

	public boolean isIdentityPk() {
		return identityPk;
	}
	
	public List<EntityAttribute> getAttributeList() {
		return list;
	}
	
	/**
	 * 将ResultSet结果集写到Entity实体对象中
	 * @param rs ResultSet结果集
	 * @param columnNames 字段名称集合
	 * @param target Entity对象
	 */
	public void setResult(final ResultSet rs, List<String> columnNames, final BaseObject target) {
		if (columnNames == null || columnNames.isEmpty())
			return;
		try {
			for (String key : columnNames) {
				invokeSet(key, target, rs.getObject(key));
			}
		} catch (SQLException e) {
			throw new DAORunTimeException(e);
		}
	}
	
	/**
	 * 将ResultSet结果集写到Entity实体对象中
	 * @param result Map结果集
	 * @param target Entity对象
	 * @param isNeedDataFilter 
	 * @param dataPermission 
	 */
	public void setResult(Map<String, Object> result, final BaseObject target) {
		if (result == null || result.isEmpty())
			return;
		for (String key : result.keySet()) {
			
			invokeSet(key, target, result.get(key));
		}
	}
	
	/**
	 * 调用实体对象的setter方法
	 * @param columnName 字段名
	 * @param target 实体对象
	 * @param args 参数
	 */
	public void invokeSet(String columnName, BaseObject target, Object... args) {
		if (columnSetterMap.containsKey(columnName)) {
			invokeSet(columnSetterMap.get(columnName), target, args);
		} else {
			target.addExtend(columnName, args[0]);
		}
	}
	
	/**
	 * 调用实体对象的setter方法
	 * @param method setter方法
	 * @param target 实体对象
	 * @param args 参数
	 */
	public void invokeSet(Method method, BaseObject target, Object... args) {
		try {
			method.invoke(target, args);
		} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
			throw new DAORunTimeException(e);
		}
	}


	/**
	 * @return the uUIDPk
	 */
	public boolean isUUIDPk() {
		return UUIDPk;
	}
	
	
	public boolean isEntity() {
		return hasAnnotation;
	}
	
	private void searchEntity(Class<? extends BaseEntity> entityClass) {
		Entity annotation = entityClass.getAnnotation(Entity.class);
		if(annotation == null) {
			hasAnnotation = false;
			return;
		}
		name = annotation.name();
		type = annotation.type();
		identityPk = annotation.isIdentityPk();
		UUIDPk = annotation.isUUIDPk();
		Field[] fields = entityClass.getDeclaredFields();
		Map<String, Method> methodNames = new HashMap<String, Method>(fields.length);
		for(Method method : entityClass.getMethods()) {
			if(method.getName().startsWith("set")) {
				methodNames.put(method.getName(), method);
			}
		}
		for(Field field : fields) {
			Column column = field.getAnnotation(Column.class);
			if(column == null) {
				continue;
			} else {
				EntityAttribute entityAttribute = new EntityAttribute();
				entityAttribute.setPk(column.isPK());
				entityAttribute.setNotNull(column.isNotNull());
				entityAttribute.setName(column.name());
				entityAttribute.setLength(column.length());
				entityAttribute.setPrecision(column.precision());
				entityAttribute.setScale(column.scale());
				entityAttribute.setAttributeName(field.getName());
				entityAttribute.setSetterMethod(methodNames.get(entityAttribute.setterName()));
				entityAttribute.setNoInsert(column.isNoInsert());
				entityAttribute.setNoUpdate(column.isNoUpdate());
				//entityAttribute.setJdbcType(column.jdbcType());
				columnSetterMap.put(column.name(), methodNames.get(entityAttribute.setterName()));
				if(column.isPK()) {
					pkMap.put(column.name(), entityAttribute);
				}
				list.add(entityAttribute);
			}
		}
	}

}